<?php

namespace app\api\service;

use app\common\cache\SmsVerifyCache;
use app\common\cache\WebScanCodeCache;
use app\common\model\user\User;
use app\common\service\UserService;
use tmcore\base\BaseService;
use tmcore\exceptions\ValidateException;
use tmcore\services\wechat\WxApService;
use tmcore\services\wechat\WxApUserService;
use tmcore\services\wechat\WxOaService;
use tmcore\services\wechat\WxOpService;
use tmcore\services\wechat\WxOaUserService;
use tmcore\services\wechat\WxOpUserService;

class LoginService extends BaseService
{
    /**
     * 用户账号/手机号登录
     * @param array $params
     * @return array|bool
     */
    public static function login($params) {
        try {
            if($params['login_type'] == 1) {
                $where['account'] = $params['account'];
                $where['password'] = User::getPassword($params['password'], 'user_register');
            } else {
                $where['mobile'] = $params['mobile'];
            }

            if($params['login_type'] == 2 && isset($params['code'])) { // 验证码检验
                (new SmsVerifyCache)->verifySmsCode($params['mobile'], 'user_login', $params['code']);
            }

            $user = User::where($where)->findOrEmpty();
            if ($user->isEmpty()) throw new ValidateException('用户登录失败');
            if ($user->status == 0) throw new ValidateException('用户已禁用，请联系管理员');

            //更新登录信息
            $user->last_time = time();
            $user->last_ip = request()->ip();
            $user->save();

            //设置token
            $tokeInfo = ApiTokenService::setToken($user->id, $params['channel'], true);

            if($params['login_type'] == 2) (new SmsVerifyCache)->deleteSmsCode($params['mobile'], 'user_login');

            // 异步事件
            (new UserService)->callEvent('user_login', $user->id);

            //返回用户信息
            return [
                'account' => $user['account'],
                'nickname' => $user['nickname'],
                'avatar' => $user['avatar'],
                'mobile' => $user['mobile'],
                'token' => $tokeInfo['token'],
            ];
        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }

    /**
     * 用户注册
     * @param array $params
     * @return bool|array
     */
    public static function register($params) {
        self::beginTrans();
        try {

            $user = (new UserService)->register($params);

            //设置token
            $tokeInfo = ApiTokenService::setToken($user['id'], $params['channel'], true);
            self::commitTrans();

            // 异步事件
            (new UserService)->callEvent('user_login', $user['id']);

            //返回用户信息
            return [
                'account' => $user['account'],
                'nickname' => $user['nickname'],
                'avatar' => $user['avatar'],
                'mobile' => $user['mobile'],
                'token' => $tokeInfo['token'],
            ];
        } catch (\Exception $e) {
            self::rollbackTrans();
            return self::setError($e->getMessage());
        }
    }

    /**
     * 用户登出
     * @param $userInfo
     * @return bool
     */
    public static function logout($userInfo) {
        //token不存在，不注销
        if (!isset($userInfo['token'])) return false;

        //清空token
        return ApiTokenService::clearToken($userInfo['id'], $userInfo['token']);
    }

    /**
     * 微信公众号跳转url
     * @param $url
     * @return string
     */
    public static function getWxOaCodeUrl($url) {
        return (new WxOaService)->getCodeUrl($url);
    }

    /**
     * 微信公众号登录
     * @param $params
     * @return bool|array
     */
    public static function wxOaLogin($params) {
        self::beginTrans();
        try {
            $info = (new WxOaService)->getOaInfoByCode($params['code']);
            $wxUser = (new WxOaUserService)->authUserLogin($info);

            //设置token
            $tokeInfo = ApiTokenService::setToken($wxUser['uid'], $params['channel'], true);

            self::commitTrans();

            // 异步事件
            (new UserService)->callEvent('user_login', $wxUser['uid']);

            $user = User::master()->where(['id' => $wxUser['uid']])->findOrEmpty();

            //返回用户信息
            return [
                'account' => $user['account'],
                'nickname' => $user['nickname'],
                'avatar' => $user['avatar'],
                'mobile' => $user['mobile'],
                'token' => $tokeInfo['token'],
            ];
        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }

    /**
     * 获取微信扫码登录二维码
     * @param $url
     * @return bool|array
     */
    public static function getWxOpScanCodeUrl($url) {
        try {
            // 获取唯一标识
            $code = md5(mt_rand(0, 99999) . time());
            (new WebScanCodeCache())->setScanCode($code);

            // 扫码超时不可登录
            $url = (new WxOpService)->getCodeUrl($url, $code);
            return ['url' => $url];

        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }

    /**
     * 微信扫码登录
     * @param $params
     * @return array|bool
     */
    public static function wxScanLogin($params) {
        self::beginTrans();
        try {
            $wxOpService = (new WxOpService);

            $info = $wxOpService->getUserAuthByCode($params['code']);
            $authUser = $wxOpService->getUserInfoByAuth($info['access_token'], $info['openid']);
            $wxUser = (new WxOpUserService)->authUserLogin($authUser);

            //设置token
            $tokeInfo = ApiTokenService::setToken($wxUser['uid'], $params['channel'], true);

            self::commitTrans();

            // 异步事件
            (new UserService)->callEvent('user_login', $wxUser['uid']);

            $user = User::master()->where(['id' => $wxUser['uid']])->findOrEmpty();

            //返回用户信息
            return [
                'account' => $user['account'],
                'nickname' => $user['nickname'],
                'avatar' => $user['avatar'],
                'mobile' => $user['mobile'],
                'token' => $tokeInfo['token'],
            ];
        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }

    /**
     * 微信小程序登录
     * @param $params
     * @return array|bool
     */
    public static function wxApLogin($params) {
        self::beginTrans();
        try {
            $info = (new WxApService)->getApInfoByCode($params['code']);
            $wxUser = (new WxApUserService)->authUserLogin($info);

            //设置token
            $tokeInfo = ApiTokenService::setToken($wxUser['uid'], $params['channel'], true);

            self::commitTrans();

            // 异步事件
            (new UserService)->callEvent('user_login', $wxUser['uid']);

            $user = User::master()->where(['id' => $wxUser['uid']])->findOrEmpty();

            //返回用户信息
            return [
                'account' => $user['account'],
                'nickname' => $user['nickname'],
                'avatar' => $user['avatar'],
                'mobile' => $user['mobile'],
                'token' => $tokeInfo['token'],
            ];
        } catch (\Exception $e) {
            return self::setError($e->getMessage());
        }
    }

    /**
     * 忘记密码
     * @param $params
     * @return array|bool
     */
    public static function forgetPassword($params) {
        self::beginTrans();
        try {

            (new SmsVerifyCache)->verifySmsCode($params['mobile'], 'retrieve_password', $params['code']);

            $where['mobile'] = $params['mobile'];
            $user = User::where($where)->findOrEmpty();
            if ($user->isEmpty()) throw new ValidateException('找不到用户');

            $params['id'] = $user['id'];
            (new UserService())->updateInfo('update_password', $params);

            (new SmsVerifyCache)->deleteSmsCode($params['mobile'], 'retrieve_password');

            return [];

        } catch (\Exception $e) {
            self::rollbackTrans();
            return self::setError($e->getMessage());
        }
    }

}